import pandas as pd
from typing import List, Dict, Optional
from datetime import datetime, timedelta
from django.db import transaction, models
from django.db.models import Q
from stocks.models import Stock, Strategy, BuySignal
from stocks.services.signal_generator import StrategyExecutor


class StrategyService:
    """策略分析服务"""
    
    @staticmethod
    def analyze_single_stock(symbol: str) -> List[Dict]:
        """
        分析单只股票
        
        Args:
            symbol: 股票代码
            
        Returns:
            分析结果列表
        """
        try:
            # 验证股票存在
            stock = Stock.objects.get(symbol=symbol)
            
            # 执行所有策略分析
            signals = StrategyExecutor.execute_all_strategies(symbol)
            
            # 为每个信号添加股票信息
            for signal in signals:
                signal['symbol'] = symbol
                signal['stock_name'] = stock.name
            
            return signals
            
        except Stock.DoesNotExist:
            print(f"股票 {symbol} 不存在")
            return []
        except Exception as e:
            print(f"分析股票 {symbol} 时出错: {e}")
            return []

    @staticmethod
    def analyze_single_stock_with_strategy(symbol: str, strategy_id: int) -> List[Dict]:
        """
        使用特定策略分析单只股票
        
        Args:
            symbol: 股票代码
            strategy_id: 策略ID
            
        Returns:
            分析结果列表
        """
        try:
            # 验证股票存在
            stock = Stock.objects.get(symbol=symbol)
            
            # 执行特定策略分析
            signals = StrategyExecutor.execute_strategy(strategy_id, symbol)
            
            # 为每个信号添加股票信息
            for signal in signals:
                signal['symbol'] = symbol
                signal['stock_name'] = stock.name
                signal['strategy_id'] = strategy_id
            
            return signals
            
        except Stock.DoesNotExist:
            print(f"股票 {symbol} 不存在")
            return []
        except Exception as e:
            print(f"使用策略 {strategy_id} 分析股票 {symbol} 时出错: {e}")
            return []
    
    @staticmethod
    def analyze_all_stocks(batch_size: int = 50) -> Dict:
        """
        分析所有股票
        
        Args:
            batch_size: 每批处理的股票数量
            
        Returns:
            分析结果统计
        """
        results = {
            'total_stocks': 0,
            'analyzed_stocks': 0,
            'total_signals': 0,
            'saved_signals': 0,
            'start_time': datetime.now(),
            'end_time': None,
            'errors': []
        }
        
        try:
            # 获取所有股票
            all_stocks = Stock.objects.all()
            results['total_stocks'] = all_stocks.count()
            
            all_signals = []
            
            # 分批处理股票
            for i in range(0, len(all_stocks), batch_size):
                batch = all_stocks[i:i + batch_size]
                
                for stock in batch:
                    try:
                        signals = StrategyService.analyze_single_stock(stock.symbol)
                        all_signals.extend(signals)
                        results['analyzed_stocks'] += 1
                        
                        if signals:
                            print(f"股票 {stock.symbol} 发现 {len(signals)} 个信号")
                            
                    except Exception as e:
                        error_msg = f"分析股票 {stock.symbol} 时出错: {str(e)}"
                        results['errors'].append(error_msg)
                        print(error_msg)
            
            results['total_signals'] = len(all_signals)
            
            # 保存信号到数据库
            if all_signals:
                saved_count = StrategyExecutor.save_signals(all_signals)
                results['saved_signals'] = saved_count
                print(f"成功保存 {saved_count} 个买入信号")
            
        except Exception as e:
            error_msg = f"批量分析股票时出错: {str(e)}"
            results['errors'].append(error_msg)
            print(error_msg)
        
        results['end_time'] = datetime.now()
        results['duration'] = results['end_time'] - results['start_time']
        
        return results
    
    @staticmethod
    def get_recent_signals(days: int = 7, min_strength: float = 50) -> List[Dict]:
        """
        获取近期买入信号
        
        Args:
            days: 最近多少天内的信号
            min_strength: 最小信号强度
            
        Returns:
            买入信号列表
        """
        try:
            cutoff_date = datetime.now().date() - timedelta(days=days)
            
            signals = BuySignal.objects.select_related(
                'strategy'
            ).filter(
                signal_date__gte=cutoff_date,
                signal_strength__gte=min_strength
            ).order_by('-signal_date', '-signal_strength')
            
            result = []
            for signal in signals:
                # 由于跨数据库问题，不能直接访问signal.stock
                # 需要单独查询股票信息
                try:
                    stock = Stock.objects.get(symbol=signal.stock)
                    symbol = stock.symbol
                    stock_name = stock.name
                except Stock.DoesNotExist:
                    symbol = signal.stock  # 使用stock作为symbol
                    stock_name = "未知股票"
                
                result.append({
                    'id': signal.id,
                    'symbol': symbol,
                    'stock_name': stock_name,
                    'strategy_name': signal.strategy.name,
                    'signal_date': signal.signal_date,
                    'signal_price': float(signal.signal_price),
                    'signal_strength': float(signal.signal_strength),
                    'reason': signal.reason,
                    'created_at': signal.created_at
                })
            
            return result
            
        except Exception as e:
            print(f"获取近期信号时出错: {e}")
            return []
    
    @staticmethod
    def get_stock_signals(symbol: str, days: int = 30) -> List[Dict]:
        """
        获取某只股票的买入信号
        
        Args:
            symbol: 股票代码
            days: 最近多少天内的信号
            
        Returns:
            买入信号列表
        """
        try:
            cutoff_date = datetime.now().date() - timedelta(days=days)
            
            signals = BuySignal.objects.select_related(
                'strategy'
            ).filter(
                stock__symbol=symbol,
                signal_date__gte=cutoff_date
            ).order_by('-signal_date', '-signal_strength')
            
            result = []
            for signal in signals:
                result.append({
                    'id': signal.id,
                    'strategy_name': signal.strategy.name,
                    'signal_date': signal.signal_date,
                    'signal_price': float(signal.signal_price),
                    'signal_strength': float(signal.signal_strength),
                    'reason': signal.reason,
                    'created_at': signal.created_at
                })
            
            return result
            
        except Exception as e:
            print(f"获取股票 {symbol} 信号时出错: {e}")
            return []

    @staticmethod
    def get_stock_all_signals(symbol: str, days: int = 30, min_strength: float = 50, strategy_id: str = '') -> List[Dict]:
        """
        获取某只股票的所有买入信号（支持筛选）
        
        Args:
            symbol: 股票代码
            days: 最近多少天内的信号
            min_strength: 最小信号强度
            strategy_id: 策略ID筛选
            
        Returns:
            买入信号列表
        """
        try:
            cutoff_date = datetime.now().date() - timedelta(days=days)
            
            # 构建查询条件
            filters = Q(
                stock__symbol=symbol,
                signal_date__gte=cutoff_date,
                signal_strength__gte=min_strength
            )
            
            if strategy_id:
                filters &= Q(strategy_id=strategy_id)
            
            signals = BuySignal.objects.select_related('strategy').filter(
                filters
            ).order_by('-signal_date', '-signal_strength')
            
            result = []
            for signal in signals:
                result.append({
                    'id': signal.id,
                    'symbol': symbol,
                    'stock_name': signal.stock.name if hasattr(signal, 'stock') else "未知股票",
                    'strategy_name': signal.strategy.name,
                    'strategy_id': signal.strategy.id,
                    'signal_date': signal.signal_date,
                    'signal_price': float(signal.signal_price),
                    'signal_strength': float(signal.signal_strength),
                    'reason': signal.reason,
                    'created_at': signal.created_at
                })
            
            return result
            
        except Exception as e:
            print(f"获取股票 {symbol} 所有信号时出错: {e}")
            return []
    
    @staticmethod
    def get_strategy_performance(strategy_id: int, days: int = 90) -> Dict:
        """
        获取策略表现统计
        
        Args:
            strategy_id: 策略ID
            days: 统计最近多少天的表现
            
        Returns:
            策略表现数据
        """
        try:
            strategy = Strategy.objects.get(id=strategy_id)
            cutoff_date = datetime.now().date() - timedelta(days=days)
            
            # 获取策略生成的信号 - 使用SQLite数据库
            signals = BuySignal.objects.filter(
                strategy=strategy,
                signal_date__gte=cutoff_date
            )
            
            total_signals = signals.count()
            
            # 计算平均信号强度
            avg_strength = signals.aggregate(avg=models.Avg('signal_strength'))['avg'] or 0
            
            # 按股票统计 - 避免跨数据库关联查询
            stock_stats = []
            for signal in signals:
                try:
                    # 手动查询股票信息
                    stock = Stock.objects.using('postgres').get(symbol=signal.stock)
                    stock_stats.append({
                        'stock__symbol': stock.symbol,
                        'stock__name': stock.name,
                        'count': 1,  # 手动计数
                        'avg_strength': float(signal.signal_strength)
                    })
                except Stock.DoesNotExist:
                    # 如果股票不存在，使用stock作为symbol
                    stock_stats.append({
                        'stock__symbol': signal.stock,
                        'stock__name': "未知股票",
                        'count': 1,
                        'avg_strength': float(signal.signal_strength)
                    })
            
            # 按日期统计
            date_stats = signals.values('signal_date').annotate(
                count=models.Count('id')
            ).order_by('-signal_date')
            
            # 合并相同股票的统计
            merged_stock_stats = {}
            for stat in stock_stats:
                symbol = stat['stock__symbol']
                if symbol in merged_stock_stats:
                    merged_stock_stats[symbol]['count'] += stat['count']
                    # 重新计算平均强度
                    current_avg = merged_stock_stats[symbol]['avg_strength']
                    current_count = merged_stock_stats[symbol]['count'] - 1
                    new_avg = (current_avg * current_count + stat['avg_strength']) / (current_count + 1)
                    merged_stock_stats[symbol]['avg_strength'] = new_avg
                else:
                    merged_stock_stats[symbol] = stat
            
            return {
                'strategy_name': strategy.name,
                'strategy_type': strategy.get_strategy_type_display(),
                'total_signals': total_signals,
                'avg_strength': float(avg_strength),
                'stock_stats': list(merged_stock_stats.values()),
                'date_stats': list(date_stats),
                'period_days': days
            }
            
        except Strategy.DoesNotExist:
            return {'error': '策略不存在'}
        except Exception as e:
            print(f"获取策略表现时出错: {e}")
            return {'error': str(e)}
    
    @staticmethod
    def cleanup_old_signals(days: int = 365):
        """
        清理旧的买入信号
        
        Args:
            days: 保留多少天内的信号
        """
        try:
            cutoff_date = datetime.now().date() - timedelta(days=days)
            
            deleted_count, _ = BuySignal.objects.filter(
                signal_date__lt=cutoff_date
            ).delete()
            
            print(f"清理了 {deleted_count} 个旧信号（{days}天前）")
            return deleted_count
            
        except Exception as e:
            print(f"清理旧信号时出错: {e}")
            return 0


# 工具函数
def test_strategy_analysis():
    """测试策略分析功能"""
    print("开始测试策略分析...")
    
    # 测试单只股票分析
    test_symbol = "000001"  # 平安银行
    signals = StrategyService.analyze_single_stock(test_symbol)
    
    print(f"\n股票 {test_symbol} 分析结果:")
    print(f"发现 {len(signals)} 个买入信号")
    
    for i, signal in enumerate(signals, 1):
        print(f"\n信号 {i}:")
        print(f"  策略: {signal['strategy_name']}")
        print(f"  日期: {signal['signal_date']}")
        print(f"  价格: {signal['signal_price']}")
        print(f"  强度: {signal['signal_strength']:.1f}")
        print(f"  理由: {signal['reason']}")
    
    # 测试获取近期信号
    recent_signals = StrategyService.get_recent_signals(days=7, min_strength=60)
    print(f"\n近期高强度信号（强度≥60）: {len(recent_signals)} 个")
    
    return signals


if __name__ == "__main__":
    # 直接运行时的测试代码
    test_strategy_analysis()
